﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.CodeDom.Compiler;

namespace Compiler.Compiler.CSharp
{
    public class CSharpMethodCompiler : ICompiler
    {
        public bool Compile(string taskName, string code, string language, List<ParamInfo> paramInfos, List<string> references, List<string> usings, out List<string> message)
        {
            if (string.IsNullOrWhiteSpace(code))
                throw new ArgumentNullException();
            if (string.IsNullOrWhiteSpace(language))
                throw new ArgumentNullException();

            message = new List<string>();

            StringBuilder source = new StringBuilder();
            List<string> defaultUsings = DefaultValueGetter.GetDefaultUsingNamespaces();
            defaultUsings.ForEach(d => source.AppendLine(string.Format("using {0};", d)));
            if (usings != null && usings.Count > 0)
                usings.ForEach(u =>
                {
                    if (!defaultUsings.Contains(u))
                        source.AppendLine(string.Format("using {0};", u));
                });

            source.AppendLine(string.Format("public class {0}:Task", taskName));
            source.AppendLine("{");
            if (paramInfos != null && paramInfos.Count > 0)
            {
                paramInfos.ForEach(p =>
                {
                    source.Append(string.Format("public {0} {1}", p.Type, p.Name));
                    source.Append("{get; set;}");
                });
            }
            source.AppendLine(code);
            source.AppendLine("}");

            CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateExecutable = false;
            List<string> defaultReferencedAssemblies = DefaultValueGetter.GetDefaultReferencedAssemblies();
            defaultReferencedAssemblies.ForEach(d => parameters.ReferencedAssemblies.Add(d));
            if (references != null && references.Count > 0)
                references.ForEach(r =>
                {
                    if (!defaultReferencedAssemblies.Contains(r))
                        parameters.ReferencedAssemblies.Add(r);
                });

            CodeDomProvider provider = CodeDomProvider.CreateProvider(language);
            CompilerResults result = provider.CompileAssemblyFromSource(parameters, source.ToString());
            if (result.Errors.Count > 0)
            {
                foreach (CompilerError error in result.Errors)
                    message.Add(error.ErrorText);
                return false;
            }
            else
                return true;
        }
    }
}
